#' Reformat MODIS "composite_day_of_the_year" SDS
#' 
#' @description 
#' In order to create custom temporal aggregation levels (e.g., half-monthly, 
#' monthly) from native 16-day MODIS composites, a convenient representation of 
#' the pixel-wise acquisition date is urgently required. Since the MODIS 
#' "composite_day_of_the_year" SDS merely includes the day of the year (DOY), 
#' but not the year itself, this function creates complete date information from 
#' both the respective MODIS layer name and the pixel-wise DOY information. 
#' 
#' @param x \code{character} or \code{Raster*}. MODIS 
#' "composite_day_of_the_year" layer(s).
#' @param cores \code{integer}. Number of cores for parallel processing.
#' @param ... Additional arguments passed to \code{\link{extractDate}}.
#' 
#' @return 
#' A \code{Raster*} object.
#' 
#' @author 
#' Florian Detsch
#' 
#' @seealso 
#' \code{\link{repDoy}}.
#' 
#' @examples 
#' \dontrun{
#' tfs = runGdal("MOD13Q1", collection = "006",
#'               begin = "2000353", end = "2000366", extent = "Luxembourg", 
#'               job = "reformatDOY", SDSstring = "000000000010")
#'         
#' ## raw doy
#' raw <- raster(unlist(tfs))
#' unique(raw[])
#' 
#' ## reformatted dates
#' rfm <- reformatDOY(raw)
#' unique(rfm[])
#' }
#' 
#' @export reformatDOY
#' @name reformatDOY
reformatDOY <- function(x, cores = 1L, ...) {

  ## if 'x' represents filename(s), import as 'Raster*'
  if (inherits(x, "character"))
    x <- raster::stack(x)
    
  ## extract required date information
  dts <- extractDate(x, ...)$inputLayerDates
  yrs <- as.numeric(substr(dts, 1, 4))
  dys <- as.numeric(substr(dts, 5, 7))

  ## initialize parallel cluster and export required objects
  cl <- parallel::makePSOCKcluster(cores)
  on.exit(parallel::stopCluster(cl))
  
  parallel::clusterExport(cl, c("x", "yrs", "dys"), envir = environment())

  ## loop over layers
  rfm <- do.call(
    raster::stack,
    parallel::parLapply(cl, 1:raster::nlayers(x), function(i) {
      # get doy values
      rst <- raster::subset(x, i)
      val <- raster::getValues(rst)


      # if required (i.e., if file date and pixel-based doy differ by more than 
      # 300 days), add +1 to year information of the respective pixel
      yr <- rep(yrs[i], length(val))

      dff <- unique(val) - dys[i]

      if (any(dff < (-300), na.rm = TRUE)) {
        ids <- which(dff < (-300))
        nxt <- unique(val)[ids]

        ids <- which(val %in% nxt)
        yr[ids] <- yr[ids] + 1
      }

      # insert new date values into raster layer
      val <- formatC(val, width = 3, flag = "0")
      val <- suppressWarnings(as.integer(paste0(yr, val)))
      raster::setValues(rst, val)
    })
  )

  ## if length(x) == 1, return 'RasterLayer'
  if (raster::nlayers(rfm) == 1) {
    rfm[[1]]
  ## else return 'RasterStack'  
  } else {
    rfm
  }
}
